package com.meituan.catering.management.product.biz.service.impl;

import com.meituan.catering.management.common.exception.BizException;
import com.meituan.catering.management.common.model.biz.PageBO;
import com.meituan.catering.management.common.model.biz.UserContextBO;
import com.meituan.catering.management.common.model.enumeration.ErrorCode;
import com.meituan.catering.management.product.biz.model.ProductDetailBO;
import com.meituan.catering.management.product.biz.model.converter.*;
import com.meituan.catering.management.product.biz.model.request.*;
import com.meituan.catering.management.product.biz.service.ProductBizService;
import com.meituan.catering.management.product.dao.converter.ProductDOConverter;
import com.meituan.catering.management.product.dao.converter.SearchProductDataConverter;
import com.meituan.catering.management.product.dao.mapper.ProductAccessoryMapper;
import com.meituan.catering.management.product.dao.mapper.ProductMapper;
import com.meituan.catering.management.product.dao.mapper.ProductMethodMapper;
import com.meituan.catering.management.product.dao.model.ProductAccessoryDO;
import com.meituan.catering.management.product.dao.model.ProductDO;
import com.meituan.catering.management.product.dao.model.ProductMethodDO;
import com.meituan.catering.management.product.dao.model.request.SearchProductDataRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.*;

/**
 * {@link ProductBizService}的核心实现
 */
@Service
public class ProductBizServiceImpl implements ProductBizService {

    @Resource
    private TransactionTemplate transactionTemplate;

    @Resource
    private ProductAccessoryMapper productAccessoryMapper;

    @Resource
    private ProductMethodMapper productMethodMapper;

    @Resource
    private ProductMapper productMapper;

    @Override
    public PageBO searchShopPage(UserContextBO userContextBO, SearchProductBizRequest request) {
        SearchProductDataRequest DataRequest = SearchProductDataConverter.toSearchProductDataRequest(request);
        int countForPage = productMapper.countForPage(DataRequest);
        if (countForPage == 0) {
            return null;
        }
        List<ProductDO> productDOS = productMapper.searchForPage(DataRequest);
        return PageBOConverter.toPageBO(productDOS, request, countForPage);
    }

    @Override
    public ProductDetailBO findById(UserContextBO userContextBO, Long id) {
        List<ProductAccessoryDO> accessoryDOList = productAccessoryMapper.findAllByProductId(userContextBO.getTenantId(), id);
        List<ProductMethodDO> methodDOList = productMethodMapper.findAllByProductId(userContextBO.getTenantId(), id);
        ProductDO productDO = productMapper.findById(userContextBO.getTenantId(), userContextBO.getUserId(), id);
        return ProductDetailBOConverter.toProductDetailBO(
                ProductBOConverter.toProductBO(productDO),
                ProductAccessoryBOConverter.toProductAccessoryBO(accessoryDOList),
                ProductMethodBOConverter.toProductMethodBO(methodDOList)
        );
    }

    @Override
    public List<ProductDetailBO> findByIds(Long tenantId, Set<Long> ids) {
        List<ProductAccessoryDO> accessoryDOList = productAccessoryMapper.findAllByProductIds(tenantId, ids);
        Map<Long, List<ProductAccessoryDO>> accessoryMap = new HashMap<>();
        for (ProductAccessoryDO productAccessoryDO : accessoryDOList) {
            if (accessoryMap.containsKey(productAccessoryDO.getProductId())) {
                List<ProductAccessoryDO> accessoryDOS = accessoryMap.get(productAccessoryDO.getProductId());
                accessoryDOS.add(productAccessoryDO);
            } else {
                List<ProductAccessoryDO> accessoryDOS = new LinkedList<>();
                accessoryDOS.add(productAccessoryDO);
                accessoryMap.put(productAccessoryDO.getProductId(), accessoryDOS);
            }
        }
        List<ProductMethodDO> methodDOList = productMethodMapper.findAllByProductIds(tenantId, ids);
        Map<Long, List<ProductMethodDO>> methodMap = new HashMap<>();
        for (ProductMethodDO productMethodDO : methodDOList) {
            if (methodMap.containsKey(productMethodDO.getProductId())) {
                List<ProductMethodDO> methodDOS = methodMap.get(productMethodDO.getProductId());
                methodDOS.add(productMethodDO);
            } else {
                List<ProductMethodDO> methodDOS = new LinkedList<>();
                methodDOS.add(productMethodDO);
                methodMap.put(productMethodDO.getProductId(), methodDOS);
            }
        }
        List<ProductDO> productDOList = productMapper.findByIds(tenantId, ids);
        return ProductDetailBOConverter.toProductDetailBOList(accessoryMap, methodMap, productDOList);
    }

    @Override
    public ProductDetailBO create(UserContextBO userContextBO, CreateProductBizRequest createProductBizRequest) throws BizException {
        ProductDO productDO = ProductDOConverter.toProductDO(userContextBO.getTenantId(), userContextBO.getUserId(), createProductBizRequest);
        List<ProductAccessoryDO> productAccessoryDOList = ProductDOConverter.toCreateAccessoryDO(userContextBO.getTenantId(), createProductBizRequest.getAccessoryGroups());
        List<ProductMethodDO> productMethodDOList = ProductDOConverter.toCreateMethodDO(userContextBO.getTenantId(), productDO.getId(), createProductBizRequest.getMethodGroups());
        Boolean flag = transactionTemplate.execute(status -> {
            int productRowCount = productMapper.insert(productDO);
            if (productRowCount == 0) {
                status.setRollbackOnly();
                return false;
            }
            if (productAccessoryDOList.size() > 0) {
                int accessoryRowCount = productAccessoryMapper.insertList(productDO.getId(), productAccessoryDOList);
                if (accessoryRowCount != productAccessoryDOList.size()) {
                    status.setRollbackOnly();
                    return false;
                }
            }
            if (productMethodDOList.size() > 0) {
                int methodRowCount = productMethodMapper.insertList(productDO.getId(), productMethodDOList);
                if (methodRowCount != productMethodDOList.size()) {
                    status.setRollbackOnly();
                    return false;
                }
            }
            return true;
        });
        if (!flag) {
            throw new BizException(ErrorCode.SYSTEM_ERROR);
        }
        return findById(userContextBO, productDO.getId());
    }

    @Override
    public ProductDetailBO update(UserContextBO userContextBO, Long id, UpdateProductBizRequest updateProductBizRequest) throws BizException {
        ProductDO productDO = ProductDOConverter.toProductDO(userContextBO.getTenantId(), userContextBO.getUserId(), id, updateProductBizRequest);
        //对加料进行过滤
        List<ProductAccessoryDO> productAccessoryDOList = ProductDOConverter.toUpdateAccessoryDO(userContextBO.getTenantId(), productDO.getId(),
                updateProductBizRequest.getAccessoryGroups());
        List<ProductAccessoryDO> queryAccessoryList = productAccessoryMapper.findAllByProductId(userContextBO.getTenantId(), id);
        List<ProductAccessoryDO> updateAccessoryList = ProductAccessoryFilter.toUpdateList(productAccessoryDOList, queryAccessoryList);
        List<ProductAccessoryDO> insertList = ProductAccessoryFilter.toInsertList(productAccessoryDOList, queryAccessoryList);
        //对做法进行过滤
        List<ProductMethodDO> productMethodDOList = ProductDOConverter.toUpdateMethodDO(userContextBO.getTenantId(), productDO.getId(),
                updateProductBizRequest.getMethodGroups());
        List<ProductMethodDO> queryMethodList = productMethodMapper.findAllByProductId(userContextBO.getTenantId(), id);
        List<ProductMethodDO> updateMethodList = ProductMethodFilter.toUpdateList(productMethodDOList, queryMethodList);
        List<ProductMethodDO> insertMethodList = ProductMethodFilter.toInsertList(productMethodDOList, queryMethodList);

        Boolean flag = transactionTemplate.execute(status -> {
            int productRowCount = productMapper.updateSelective(productDO);
            if (productRowCount != 1) {
                status.setRollbackOnly();
                return false;
            }
            if (updateAccessoryList.size() > 0) {
                int updateRowCount = productAccessoryMapper.updateList(id, updateAccessoryList);
                if (updateRowCount != updateAccessoryList.size()) {
                    status.setRollbackOnly();
                    return false;
                }
            }
            if (insertList.size() > 0) {
                int insertRowCount = productAccessoryMapper.insertAll(insertList);
                if (insertRowCount != insertList.size()) {
                    status.setRollbackOnly();
                    return false;
                }
            }
            if (updateMethodList.size() > 0) {
                int updateMethodCount = productMethodMapper.updateList(updateMethodList);
                if (updateMethodCount != updateMethodList.size()) {
                    status.setRollbackOnly();
                    return false;
                }
            }
            if (insertMethodList.size() > 0) {
                int insertMethodCount = productMethodMapper.insertAll(insertMethodList);
                if (insertMethodCount != insertMethodList.size()) {
                    status.setRollbackOnly();
                    return false;
                }
            }
            return true;
        });
        if (!flag) {
            throw new BizException(ErrorCode.SYSTEM_ERROR);
        }
        return findById(userContextBO, id);
    }

    @Override
    public ProductDetailBO enabled(UserContextBO userContextBO, Long id, EnabledProductBizRequest enabledProductBizRequest) {
        int rowCount = productMapper.changeEnabledById(userContextBO.getTenantId(),
                id, enabledProductBizRequest.getEnabled(), enabledProductBizRequest.getVersion(), new Date());
        if (rowCount != 1) {
            return null;
        }
        return findById(userContextBO, id);
    }

    @Override
    public ProductDetailBO disable(UserContextBO userContextBO, Long id, DisableProductBizRequest disableProductBizRequest) {
        int rowCount = productMapper.changeEnabledById(userContextBO.getTenantId(), id,
                disableProductBizRequest.getEnabled(), disableProductBizRequest.getVersion(), new Date());
        if (rowCount != 1) {
            return null;
        }
        return findById(userContextBO, id);
    }
}
